package cn.xiaobai.captcha.server;

import cn.hutool.json.JSONUtil;
import cn.xiaobai.captcha.domain.CaptchaBean;
import cn.xiaobai.captcha.mapper.CaptchaMapper;
import cn.xiaobai.captcha.utils.ConcurrentHashMapCacheUtils;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.service.IService;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 验证码服务
 *
 * @Author yangdaji
 * @Date 2024/4/20
 * @PackageName cn.xiaobai.captcha.server
 * @ClassName CaptchServer
 */
@Slf4j
public class CaptchaServer extends ServiceImpl<CaptchaMapper, CaptchaBean> implements IService<CaptchaBean> {

    private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(3);

    private Map<Long, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>();

    private static AtomicLong count = new AtomicLong();

    /**
     * 保存或更新数据, 同时根据过期时间进行自动清理
     *
     * @param captchaBean 缓存对象
     * @param expire      过期时间
     * @param unit        时间单位
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean saveOrUpdateExpire(CaptchaBean captchaBean, long expire, TimeUnit unit) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("key_name", captchaBean.getKey_name());

        // 查询是该key 是否存在
        CaptchaBean one = this.getOne(queryWrapper);
        boolean state;
        if (Objects.nonNull(one)) {
            // 根据key 进行修改,同时刷新缓存时间
            state = this.update(captchaBean, queryWrapper);
            log.info("缓存已更新");
        } else {
            state = this.save(captchaBean);
            log.info("成功保存验证码");
        }

        log.info("保存对象信息: {}", JSONUtil.toJsonStr(captchaBean));
        //加入缓存
        ConcurrentHashMapCacheUtils.setCache(captchaBean.getKey_name(), captchaBean);
        //设置有效期
        this.expiredKey(expire, unit);
        return state;
    }

    /**
     * 到期自动删除缓存key
     */
    public void expiredKey(long expire, TimeUnit unit) {

        //时间过期删除缓存key
        ScheduledFuture<?> scheduledFuture = scheduler.scheduleAtFixedRate(() -> {
            handExpiredData();
            ScheduledFuture<?> future = scheduledFutureMap.remove(count.get());
            if (future != null) {
                count.decrementAndGet();
                future.cancel(true);
            }
        }, expire, expire, unit);
        scheduledFutureMap.put(count.incrementAndGet(), scheduledFuture);
    }

    /**
     * 处理过期数据
     */
    public void handExpiredData() {
        log.info("开始清理过期缓存");
        QueryWrapper query1 = new QueryWrapper();
        query1.lt("cache_time", new Date());
        List<CaptchaBean> captchaBeanList = this.list(query1);
        if (!captchaBeanList.isEmpty()) {
            List<Integer> expiredDataList = captchaBeanList.stream()
                    .filter(d -> ConcurrentHashMapCacheUtils.checkCache(d.getKey_name()))
                    .map(CaptchaBean::getId)
                    .collect(Collectors.toList());
            ConcurrentHashMapCacheUtils.deleteTimeOut();
            // 清理过期数据
            this.removeByIds(expiredDataList);
        }
        log.info("过期数据清理完毕");
    }
}
